package framework.classification.entities;

import java.util.ArrayList;
import java.util.HashMap;

import framework.AnnuaireCocola;
import framework.classification.entities.lattice.TreillisI;
import framework.classification.library.AbstractClassfication;
import framework.entity.ACLEntity;
import framework.entity.ACLFunction;
import framework.entity.ACLParameter;

public class ClFunctionProvided extends ClAbstractEntity {

	public static String FUNCTION_PROVIDED = "Function_Provided";

	private ArrayList<ACLFunction> fonctions;

	private ACLFunction funcmodel;

	private HashMap<String,ArrayList<String>> funcNoPara;

	public ClFunctionProvided(String s, AbstractClassfication cl, TreillisI t,
			ArrayList<ACLFunction> a) {
		super(s, cl, t);

		fonctions = a;
		funcNoPara = new HashMap<String, ArrayList<String>>();
		createTableModel();
		int x = this.getAttribut().size();
		int y = this.getEntity().size();
		table = new int[x][y];
		calculPair();

		



	}

	public void createTableModel() {

		ArrayList<String> maxType = new ArrayList<String>();
	
		//pour toutes les fonctions
		for (ACLFunction func : fonctions){
			//on l'ajoute dans les entitées
			getEntity().add(func.toString());

			

			//hash comporte un model d'entree de la fonction
			HashMap<String,Integer> modelx = new HashMap<String, Integer>();

			//ajout des parametres d'entrees de la fonction
			for (String para : func.getIn()){

				//on ajoute le parametre
				if (!getAttribut().contains("IN="+para))
					getAttribut().add("IN="+para);

				//on ajoute tous les parametres enfants de parametre
				ArrayList<String> childsPara = getAbstractClassfication().getStructure().getHierarchyDown().get(para);
				for (int i=0;i<childsPara.size();i++){
					String p = childsPara.get(i);
					if (!p.equals("ANY")){
						if (!getAttribut().contains("IN="+p))
							getAttribut().add("IN="+p);
					}
				}

				//on ajoute tous les parametres parent de parametre
				ArrayList<String> parentsPara = getAbstractClassfication().getStructure().getHierarchyUp().get(para);
				for (int i=0;i<parentsPara.size();i++){

					String p = parentsPara.get(i);
					if (!p.equals("void")){
						if (!getAttribut().contains("IN="+p))
							getAttribut().add("IN="+p);
					}
				}

				//on ajoute le top du parametre dans une liste pour verifier si
				//toutes les fonctions possede bien tous les type de paramtres
				if (parentsPara.size() > 1){
					if (!maxType.contains(parentsPara.get(parentsPara.size()-2)))
						maxType.add(parentsPara.get(parentsPara.size()-2));
				}
				else if (!maxType.contains(para)) maxType.add(para);
			}


			//ajout du parametre de sortie
			if (!getAttribut().contains("OUT="+func.getOut()))
				getAttribut().add("OUT="+func.getOut());

			//on ajoute tous les parametres enfants de parametre
			ArrayList<String> childsPara = getAbstractClassfication().getStructure().getHierarchyDown().get(func.getOut());
			for (int i=0;i<childsPara.size();i++){
				String p = childsPara.get(i);
				if (!p.equals("ANY")){
					if (!getAttribut().contains("OUT="+p))
						getAttribut().add("OUT="+p);
				}
			}

			//on ajoute tous les parametres parent de parametre
			ArrayList<String> parentsPara = getAbstractClassfication().getStructure().getHierarchyUp().get(func.getOut());
			for (int i=0;i<parentsPara.size();i++){
				String p = parentsPara.get(i);
				if (!p.equals("void")){
					if (!getAttribut().contains("OUT="+p))
						getAttribut().add("OUT="+p);
				}
			}



		}

		//on verifie que toutes les fonctions possedent tous les types de parametres
		// sinon on ajoute la negation du parametre dans la table
		for (ACLFunction aclfunc : fonctions){
			for (String max : maxType){
				Boolean add = true;

				for (String p : aclfunc.getIn()){
					ArrayList<String> parentsPara = getAbstractClassfication().getStructure().getHierarchyUp().get(p);
					String paraTop = null;

					if (parentsPara.size() > 1){
						paraTop = parentsPara.get(parentsPara.size()-2);
					}
					else paraTop = p ;

					if (max.equals(paraTop)) add = false;
					else if ((getAbstractClassfication().getStructure().isParent(paraTop, max)))
						add = false;

				}
				if (add){

					if (!funcNoPara.containsKey(aclfunc.toString()))
						funcNoPara.put(aclfunc.toString(),new ArrayList<String>());
					if (!funcNoPara.get(aclfunc.toString()).contains("!"+max))
						funcNoPara.get(aclfunc.toString()).add("!"+max);

					if (!getAttribut().contains("IN=!"+max))
						getAttribut().add("IN=!"+max);
				}

			}
		}

	}
	
	public void calculPair() {
		for (int x = 0; x < this.getAttribut().size(); x++) {
			for (int y = 0; y < this.getEntity().size(); y++) {

				if (isPair(getAttribut().get(x), getEntity().get(y), y))
					table[x][y] = 1;
				else if (table[x][y] == 0)
					table[x][y] = 0;

			}
		}
	}

	protected Boolean isPair(String parametre, String operation, int y) {

		String type = parametre.substring(0, parametre.indexOf("="));
		String para = parametre.substring(parametre.indexOf("=") + 1);

		if (type.equals("IN")){

			if (para.charAt(0) == '!'){

				if (funcNoPara.containsKey(operation)){
					ArrayList<String> nopara = funcNoPara.get(operation);

					if (nopara.contains(para)){
						int indexpara = getAttribut().indexOf("IN="+para.substring(1));
						table[indexpara][y] = 1;
						return true;

					}
				}
				return false;
			}

			//le parametre parametre doit etre enfant d'un parametre inclus dans la fonction
			ACLFunction aclfunc = new ACLFunction(operation,ACLFunction.MODE2);
			for (String parafunc : aclfunc.getIn()){
				if (para.equals(parafunc))
					return true;
				if (getAbstractClassfication().getStructure().isParent(parafunc, para))
					return true;
			}
			return false;

		}
		else{

			//le paramatre parametre doit parent du parametre de sortie de la fonction
			ACLFunction aclfunc = new ACLFunction(operation,ACLFunction.MODE2);
			String parafunc = aclfunc.getOut();
			if (para.equals(parafunc))
				return true;
			if (getAbstractClassfication().getStructure().isParent(para, parafunc))
				return true;
			else return false;

		}
	}





	@Override
	public String getType() {
		// TODO Auto-generated method stub
		return FUNCTION_PROVIDED;
	}
	public ACLFunction getModelIn(){
		return funcmodel;
	}

	@Override
	public ACLEntity getACLEntity(String s) {
		// TODO Auto-generated method stub
		return null;
	}




}
